let Ci = Components.interfaces;
let Cc = Components.classes;
let Cr = Components.results;

function addGame()
{
	notifyObservers(null, 'status-changed', 'Adding game...');

	/* Create New File Picker */
	var fp = Components.classes["@mozilla.org/filepicker;1"]
		.createInstance(Ci.nsIFilePicker);

	var bundleMain = document.getElementById("bundleMain");
	var title = bundleMain.getString("selectGameDefinition");

	fp.init(window, title, Ci.nsIFilePicker.modeOpen);

	/* Append Filters to File Picker */
	fp.appendFilter("SaveDB Game Definition (*.sdgd)", "*.sdgd");
	fp.appendFilters(Ci.nsIFilePicker.filterAll);

	var res = fp.show();
	if(res == Ci.nsIFilePicker.returnOK)
	{
		/* Get FilePicker File */
		log('Selected Game File: ' + fp.fileURL.spec, SD_LOG_DEBUG2);
		var file = fp.fileURL.spec;

		var background = Cc["@mozilla.org/thread-manager;1"]
			.getService()
			.newThread(0);

		log('Dispatching Add Game thread.', SD_LOG_DEBUG2);
		background.dispatch(new gameThread(file, fp.file.path), Ci.nsIThread.DISPATCH_NORMAL);
	}
}

var gameThread = function(file, path)
{
	this.file = file;
	this.path = path;
}

gameThread.prototype = {
	run: function()
	{
		log('Processing Game Definition File.', SD_LOG_INFO);

		/* Retrieve XML from File */
		var req = new XMLHttpRequest();
		req.open("GET", this.file, false);
		req.send(null);
	
		if(!req.responseXML)
		{
			log('Error while opening Game Definition File.', SD_LOG_ERROR);

			notifyObservers(null, 'status-changed', 'An error has occurred.');
			return;
		}
			
		this.dom = req.responseXML;
	
		/* Parse XML into Game Object */
		log('Parsing Game Definition File.', SD_LOG_DEBUG);
		this._parseGame();
		if(!this.game)
		{
			log('Error while parsing Game Definition File.', SD_LOG_ERROR);
			notifyObservers(null, 'status-changed', 'An error has occurred.');
			return;
		}
	
		/* Save SaveDB Game Definition File Path to Game Object */
		log('Game File: ' + this.path, SD_LOG_DEBUG2);
		this.game.file = this.path;

		notifyObservers(null, 'game-on-response', this.game.toSource());
	},
	QueryInterface: function(iid)
	{
		if(iid.equals(Ci.nsIRunnable) || iid.equals(Ci.nsISupports))
		{
			return this;
		}
		throw Cr.NS_ERROR_NO_INTERFACE;
	},
	_parseGame: function()
	{
		/* Check for Game Definition Parsing Error */
		if(this.dom && this.dom.documentElement)
		{
			if(this.dom.documentElement.nodename && this.dom.documentElement.nodename == 'parseerror')
			{
				return;
			}
		}
	
		this.game = new Object();
	
		/* Get Game Name using XPath */
		try
		{
			var nameXPR = this.dom.evaluate('/savedb/game/name', this.dom, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
			this.game.name = nameXPR.singleNodeValue.textContent;
			log('Game: ' + this.game.name, SD_LOG_DEBUG2);
		}
		catch(ex)
		{
			log('Unable to find name element in Game Definition File.', SD_LOG_ERROR);
			return;
		}
	
		/* Get Game UUID using XPath */
		try
		{
			var uuidXPR = this.dom.evaluate('/savedb/game/uuid', this.dom, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
			this.game.uuid = uuidXPR.singleNodeValue.textContent;
			log('UUID: ' + this.game.uuid, SD_LOG_DEBUG2);
		}
		catch(ex)
		{
			log('Unable to find uuid element in Game Definition File.', SD_LOG_ERROR);
			return;
		}
	
		/* Get Game Platform using XPath */
		try
		{
			var platformXPR = this.dom.evaluate('/savedb/game/platform', this.dom, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
			this.game.platform = platformXPR.singleNodeValue.textContent;
			log('Platform: ' + this.game.platform, SD_LOG_DEBUG2);
		}
		catch(ex)
		{
			log('Unable to find platform element in Game Definition File.', SD_LOG_WARN);
			this.game.platform = 'Unknown';
		}
		 
		/* Get Filesystem Data using XPath */
		try
		{
			this.game.fsData = new Array();
			var fsDataIterator = this.dom.evaluate('/savedb/game/fsdata/location', this.dom, null, XPathResult.ANY_TYPE, null);
			var fsDataLocation = fsDataIterator.iterateNext();
			while(fsDataLocation)
			{
				log('fsData Location: ' + fsDataLocation, SD_LOG_DEBUG2);

				var path = this._findPath(fsDataLocation.textContent);
				if(path)
				{
					this.game.fsData.push(path);
				}
				fsDataLocation = fsDataIterator.iterateNext();
			}
		}
		catch(ex)
		{
			log('Unable to process filesystem locations in Game Definition File.', SD_LOG_ERROR);
			return;
		}
		
		/* Get Registry Data using XPath */
		try
		{
			this.game.regData = new Array();
			var regDataIterator = this.dom.evaluate('/savedb/game/regdata/location', this.dom, null, XPathResult.ANY_TYPE, null);
			var regDataLocation = regDataIterator.iterateNext();
			while(regDataLocation)
			{
				log('regData Location: ' + regDataLocation, SD_LOG_DEBUG2);
				this.game.regData.push(regDataLocation.textContent);
				regDataLocation = regDataIterator.iterateNext();
			}
		}
		catch(ex)
		{
			log('Unable to process registry locations in Game Definition File.', SD_LOG_ERROR);
			return;
		}
	},
	_findPath: function(path)
	{
		/* Get Available Drives */
		try
		{
			var root = Cc["@mozilla.org/file/local;1"]
				.createInstance(Ci.nsILocalFile);
			root.initWithPath("\\\\.");
		}
		catch(ex)
		{
			log('Unable to initialize root path.', SD_LOG_DEBUG2);
			return;
		}
	
		try
		{
			var drivesEnumerator = root.directoryEntries, drives = [];
			while(drivesEnumerator.hasMoreElements())
			{
				var drive = drivesEnumerator.getNext().QueryInterface(Ci.nsILocalFile).path;
				log('Drive Found: ' + drive, SD_LOG_DEBUG2);
				drives.push(drive);
			}
		}
		catch(ex)
		{
			log('Unable to enumerator drives.', SD_LOG_DEBUG2);
			return;
		}
	
		for(var i  = 0; i < drives.length; i++)
		{
			try
			{
				var pathCheck = Cc["@mozilla.org/file/local;1"]
					.createInstance(Ci.nsILocalFile);
				pathCheck.initWithPath(drives[i] + path);
				if(pathCheck.exists())
				{
					log('Path Found: ' + drives[i] + path, SD_LOG_DEBUG2);
					return pathCheck.path;
				}
			}
			catch(ex)
			{
				log('Unable to initialize drive path.', SD_LOG_DEBUG2);
				continue;
			}	
		}
	}
};
